package cn.bugstack.springframework.beans.factory.xml;

import cn.bugstack.springframework.beans.BeansException;
import cn.bugstack.springframework.beans.PropertyValue;
import cn.bugstack.springframework.core.io.Resource;
import cn.bugstack.springframework.core.io.ResourceLoader;
import cn.bugstack.springframework.beans.factory.config.BeanDefinition;
import cn.bugstack.springframework.beans.factory.config.BeanReference;
import cn.bugstack.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import cn.bugstack.springframework.beans.factory.support.BeanDefinitionRegistry;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author ouyangzhao
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {


    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        super(registry, resourceLoader);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry){
        super(registry);
    }

    @Override
    public void loadBeanDefinitions(String locations) throws BeansException {
        ResourceLoader resourceLoader = getResourceLoader();
        Resource resource = resourceLoader.getInputStream(locations);
        loadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(String... locations) throws BeansException {
        for (String location : locations) {
            loadBeanDefinitions(location);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource resource) throws BeansException {
        try {
            // 这里用try来包裹,会省掉finally里边关闭流的方法
            try(InputStream inputStream = resource.getInputStream()) {
                doLoadBeanDefinitions(inputStream);
            }
        }catch(IOException | ClassNotFoundException e){
            throw new BeansException("Could not load bean definitions:"+resource,e);
        }
    }

    @Override
    public void loadBeanDefinitions(Resource... resources) throws BeansException {
        for (Resource resource : resources){
            loadBeanDefinitions(resource);
        }
    }
    /**
     * @description:加载xml并封装BeanDefinition放入map容器中
     * @author ouyangzhao
     * @param
     * @date 2022/8/1 21:50
     * @version 1.0.6
    */
    protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, BeansException {
        Document doc = XmlUtil.readXML(inputStream);
        Element documentElement = doc.getDocumentElement();
        NodeList childNodes = documentElement.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            // 判断是否是元素
            if(!(childNodes.item(i) instanceof Element)){
                continue;
            }
            // 判断是不是bean对象
            if(!"bean".equals(childNodes.item(i).getNodeName())){
                continue;
            }
            // 解析bean标签
            Element bean = (Element) childNodes.item(i);
            String id = bean.getAttribute("id");
            String name = bean.getAttribute("name");
            String aClass = bean.getAttribute("class");
            // 通过反射拿到类的实例
            Class<?> aClass1 = Class.forName(aClass);
            String beanName = StrUtil.isNotEmpty(id) ? id : name;
            if(StrUtil.isEmpty(beanName)){
                // 拿到类名
                beanName = StrUtil.lowerFirst(aClass1.getSimpleName());
            }
            // 定义bean
            BeanDefinition beanDefinition = new BeanDefinition(aClass1);
            // 读取属性并填充
            for(int j = 0; j < bean.getChildNodes().getLength();j++){
                if(!(bean.getChildNodes().item(j) instanceof Element)){
                    continue;
                }
                // 判断是不是property属性
                if(!"property".equals(bean.getChildNodes().item(j))){
                    continue;
                }
                // 解析property标签
                Element beanProperties = (Element) bean.getChildNodes().item(j);
                String name1 = beanProperties.getAttribute("name");
                String value = beanProperties.getAttribute("value");
                String ref = beanProperties.getAttribute("ref");
                // 需要往BeanDefinition里边注入属性,判断是value还是ref的属性
                Object o = StrUtil.isNotEmpty(ref)? new BeanReference(ref):value;
                // <property name="userDao" ref="userDao"/>
                PropertyValue propertyValue = new PropertyValue(name1,o);
                // 把这些属性注入BeanReference的属性集合里边
                beanDefinition.getPropertyValues().addPropertyValue(propertyValue);

            }
            if(getRegistry().containsBeanDefinition(beanName)){
                throw new IllegalStateException("Duplicate beanName[" + beanName + "] is not allowed");
            }
            // 注册 BeanDefinition
            getRegistry().registerBeanDefinition(beanName,beanDefinition);
        }


    }
}
